﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once
#include "GcmpModel.h"
#include "IBoolOperation.h"

namespace gcmp
{
    class IElement;
    class IGraphicsBRepBody;
    class IGraphicsElementShape;
    class IInstance;
    class IGraphicsNodeIdAsker;

    /// \brief Element造型操作类
    ///
    /// 处理带拓扑命名的几何操作，内部管理id的映射关系，可使用历史追溯机制进行追溯
    class GCMP_MODEL_EXPORT GcmpElementModelingOperator
    {
    public:

        /// \brief Element 与 GRep 的关系
        enum class EnOwnerElementAndGRepRelationship : int8_t
        {
            First = 0,  /// < 第一个GRep 来自 Owner Element 
            Second,     /// < 第二个GRep 来自 Owner Element 
            Neither     /// < 第一、二个GRep 都不属于Owner Element 
        };

        /// \brief 布尔运算
        /// 
        /// 该操作取 pFirstGRep 和 pSecondGRep 里的__第一个__实体 body 进行指定类型的布尔操作，同时对结果体进行拓扑命名，拓扑命名的历史追溯信息保存在 pOwnerElement 里
        /// 注意事项：1、如果 pFirstGRep 或者 pSecondGRep 来自 pOwnerElement，请通过EnOwnerElementAndGRepRelationship正确指定其关系，来自pOwnerElement的GRep body在参与布尔运算时会保留原体的编号
        ///          2、为确保拓扑命名的唯一性，尽量给参与布尔运算的body提供一些辅助的key，以免布尔运算结果体产生重复的边、面编号
        ///
        /// \param pOwnerElement    主Element，也就是存放布尔运算结果体边、面历史追溯信息的对象
        /// \param pFirstGRep       参与布尔运算的第一个body所在的GRep
        /// \param pSecondGRep      参与布尔运算的第二个body所在的GRep
        /// \param boolType         布尔类型
        /// \param ownerElementContainGRepStatus   pFirstGRep 或者 pSecondGRep 是否来自 pOwnerElement
        /// \param auxKeyOfBodyFromFirstGRep       pFirstGRep 里参与布尔运算的体的辅助值，用于辅助生成拓扑命名
        /// \param auxKeyOfBodyFromSecondGRep      pSecondGRep 里参与布尔运算的体的辅助值，用于辅助生成拓扑命名
        /// \return 布尔运算的结果体
        static OwnerPtr<IGraphicsBRepBody> CreateBoolBodyOperation(IElement* pOwnerElement,
            const IGraphicsElementShape* pFirstGRep,
            const IGraphicsElementShape* pSecondGRep,
            BooleanOperationTypes boolType,
            EnOwnerElementAndGRepRelationship ownerElementContainGRepStatus = EnOwnerElementAndGRepRelationship::First,
            Int32 auxKeyOfBodyInFirstGRep = -1,
            Int32 auxKeyOfBodyInSecondGRep = -1);      

        /// \brief 布尔运算
        /// 
        /// 该操作进行指定类型的布尔操作，同时对结果体进行拓扑命名，拓扑命名的历史追溯信息保存在 pOwnerElement 里
        /// 注意事项：1、pthisBRepBody是来源于pOwnerElement，或者是pOwnerElement中的ModelingOperation创建出来的带拓扑命名的体
        ///          2、如果 pOtherBRepBody也是来源于pOwnerElement，或者是pOwnerElement中的ModelingOperation创建出来的带拓扑命名的体，默认参数除了bool容差其他都不需要设置
        ///          3、如果 pOtherBRepBody是来源其他element，isCopyOtherBRepBodyOperation需要设置为true,尽量给参与布尔运算的body提供一些辅助的key(比如对象id和body索引？)，以免布尔运算结果体产生重复的边、面编号
        ///
        /// \param pOwnerElement          主Element，也就是存放布尔运算结果体边、面历史追溯信息的对象
        /// \param pGraphicsNodeIdAsker   主Elemen拓扑命名查询器（主Element中ModelingOperation创建出来）
        /// \param pthisBRepBody          参与布尔运算的第一个body
        /// \param pOtherBRepBody         参与布尔运算的第二个body
        /// \param boolType               布尔类型
        /// \param isCopyOtherBRepBodyOperation   是否把pOtherBRepBody边面数据重新进行拓扑命名，并且会把拓扑命名的历史追溯信息保存在 pOwnerElement 里
        /// \param auxKey1       pOtherBRepBody 里参与布尔运算的体的辅助值，用于辅助生成拓扑命名
        /// \param auxKey2       pOtherBRepBody 里参与布尔运算的体的辅助值，用于辅助生成拓扑命名
        /// \param tolerance     容差，默认0.1
        /// \return 布尔运算的结果体
        static OwnerPtr<IGraphicsBRepBody> CreateBoolBodyOperation(IElement* pOwnerElement, 
            IGraphicsNodeIdAsker* pGraphicsNodeIdAsker,
            const IGraphicsBRepBody* pthisBRepBody,
            const IGraphicsBRepBody* pOtherBRepBody,
            BooleanOperationTypes boolType,
            double tolerance = 0.1,
            bool isCopyOtherBRepBodyOperation = false,
            ElementId auxKey1 = ElementId(-1),
            Int32 auxKey2 = -1);

        /// \brief 使用Instance中的布尔减操作对当前Instance执行扣减操作
        /// 
        /// \param pThisElement 当前Instance
        /// \param pThisGRep 被扣减的GRep,该GRep应该从属于当前Instance
        /// \param pCutterGReps 扣减体
        /// \return 布尔减操作结果
        static SubstractByOtherElementsResult SubstractByOtherElements(gcmp::IInstance* pThisElement,
            IGraphicsElementShape* pThisGRep,
            const std::vector<const IGraphicsElementShape*>& pCutterGReps);


        /// \brief 设置多少个扣减体布尔并后做一次扣减
        /// 
        /// 当扣减体数量较多时，对扣减体进行布尔并后再做扣减可以大幅提升性能。
        /// 该静态变量表示多少个扣减体合并后进行一次扣减，默认是50个
        /// \param number 扣减体布尔并的数量
        /// \return 
        static void SetNumberOfUniteCutter(int number);
    };
}


